#ifndef PW_PBL_PACKITER_HPP
#define PW_PBL_PACKITER_HPP

#include <functional>
#include "Throw.hpp"

namespace pw_pbl::pack_iter
{
	/// 从参数包中查找满足条件的第一个索引，均未满足时返回参数包大小，必须使用(find <<...<< condition)的形式，其中condition是与参数包相关的bool类型值
	constexpr struct
	{
		bool finded = false;
		size_t index = -1;

		constexpr auto operator<<(bool condition) const { return finded ? *this : (std::decay_t<decltype(*this)>){condition, index + 1}; }
		constexpr operator size_t() const { return finded ? index : index + 1; }
	} find{};

	/// 从参数包中返回满足条件的惟一索引，不是有且仅有一个满足时断言失败，必须使用(index <<...<< condition)的形式，其中condition是与参数包相关的bool类型值
	constexpr struct
	{
		bool finded = false;
		size_t index = -1;

		constexpr auto operator<<(bool condition) const { pw_pbl_assert(!(finded && condition)) return finded ? *this : (std::decay_t<decltype(*this)>){condition, index + 1}; }
		constexpr operator size_t() const { pw_pbl_assert(finded) return index; }
	} unique_find{};

	/// 从参数包中查找CMP(value, E)为真的值并返回，使用(compare<...>{} <<...<< value)从左开始查找，使用(value <<...<< compare<...>{})从右开始查找
	template <auto CMP, auto E, decltype(E) FALLBACK> requires(!CMP(FALLBACK, E))
	struct compare
	{
		using T = decltype(E);
		T v = FALLBACK;

		constexpr operator T() const { return v; }
		constexpr compare operator<<(T packv) const { return CMP(v, E) ? *this : compare{packv}; }
		friend constexpr compare operator>>(T packv, compare self) { return self << packv; }
	};

	template <auto E, decltype(E) FALLBACK = E>
	static constexpr compare<std::not_equal_to<>{}, E, E> ne{};

	template <auto E, decltype(E) FALLBACK>
	static constexpr compare<std::equal_to<>{}, E, FALLBACK> eq{};

	template <auto E, decltype(E) FALLBACK = E>
	static constexpr compare<std::greater<>{}, E, FALLBACK> gt{};

	template <auto E, decltype(E) FALLBACK>
	static constexpr compare<std::greater_equal<>{}, E, FALLBACK> ge{};

	template <auto E, decltype(E) FALLBACK = E>
	static constexpr compare<std::less<>{}, E, FALLBACK> lt{};

	template <auto E, decltype(E) FALLBACK>
	static constexpr compare<std::greater_equal<>{}, E, FALLBACK> le{};

	template <typename T>
	struct find_result
	{
		bool ok;
		T result;
		size_t index;
	};

	/// 从参数包中查找CMP(value, E)为真的值并返回，必须用(compare<...>{} <<...<< value)形式从左开始查找
	template <auto CMP, auto E, decltype(E) FALLBACK> requires(!CMP(FALLBACK, E))
	struct find_compare
	{
		using T = decltype(E);
		T v = FALLBACK;
		size_t index = -1;

		constexpr find_result<T> result() const
		{
			bool ok = CMP(v, E);
			return {.ok = ok, .result = v, .index = ok ? index : index + 1};
		}
		constexpr operator find_result<T>() const { return result(); }
		constexpr find_compare operator<<(T packv) const { return CMP(v, E) ? *this : find_compare{.v = packv, .index = index + 1}; }
	};

	template <auto E, decltype(E) FALLBACK = E>
	static constexpr find_compare<std::not_equal_to<>{}, E, E> find_ne{};

	template <auto E, decltype(E) FALLBACK>
	static constexpr find_compare<std::equal_to<>{}, E, FALLBACK> find_eq{};

	template <auto E, decltype(E) FALLBACK = E>
	static constexpr find_compare<std::greater<>{}, E, FALLBACK> find_gt{};

	template <auto E, decltype(E) FALLBACK>
	static constexpr find_compare<std::greater_equal<>{}, E, FALLBACK> find_ge{};

	template <auto E, decltype(E) FALLBACK = E>
	static constexpr find_compare<std::less<>{}, E, FALLBACK> find_lt{};

	template <auto E, decltype(E) FALLBACK>
	static constexpr find_compare<std::greater_equal<>{}, E, FALLBACK> find_le{};

} // namespace pw_pbl::pack_iter

#endif // PW_PBL_PACKITER_HPP
